package com.katesoft.scale4j.persistent.client;

import com.katesoft.scale4j.persistent.model.unified.AbstractPersistentEntity;
import com.katesoft.scale4j.persistent.types.RevisionData;
import org.springframework.dao.DataAccessException;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Convenient super class for Hibernate-based data access objects.
 * <p/>
 * This base class is mainly intended for LocalHibernateTemplate usage.
 * <p/>
 * You can find method to work with historical data here and convenient method to perform lucene
 * search operations on top of domain classes.
 * 
 * @author kate2007
 */
public interface IHibernateDaoSupport {
   /**
    * Searches for persistent entities of the given entityClass based on query string.
    * <p>
    * Note: This method must be used only if entity class is annotated with @Indexed annotation.
    * <p/>
    * Also this method can't cause {@link OutOfMemoryError} because restricts max result to
    * pre-defined maximum size.
    * <p/>
    * Search is restricted by given properties.
    * </p>
    * 
    * @param <T>
    *           type of entity.
    * @param queryString
    *           search string or <code>NULL</code>.
    * @param entityClass
    *           entity class.
    * @param properties
    *           search restriction fields.
    * @return list of founded entities.
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    * @see org.apache.lucene.search.Query
    */
   <T extends AbstractPersistentEntity> List<T> search(final String queryString,
            final Class<T> entityClass, final String[] properties) throws DataAccessException;

   /**
    * looking for latest revision of entity. latest revision always exists unless there is no such
    * entity(with given unique identifier).
    * 
    * @param entityClass
    *           domain class
    * @param uniqueIdentifier
    *           domain entity unique identifier
    * @param <T>
    *           type of entity
    * @return latest revision of entity.
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    */
   <T extends AbstractPersistentEntity> Number latestRevision(Class<T> entityClass,
            long uniqueIdentifier) throws DataAccessException;

   /**
    * looking up for the all revisions of entity(result list is sorted by revision number in
    * descending order).
    * 
    * @param entityClass
    *           domain class
    * @param uniqueIdentifier
    *           domain entity unique identifier
    * @param <T>
    *           type of entity
    * @return sorted collection of all revisions of entity.
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    */
   <T extends AbstractPersistentEntity> List<Number> allRevisions(Class<T> entityClass,
            long uniqueIdentifier) throws DataAccessException;

   /**
    * retrieve revision data information of entity(all versions ordered by revision number desc).
    * 
    * @param entityClass
    *           domain class
    * @param uniqueIdentifier
    *           domain entity unique identifier
    * @param <T>
    *           type of entity
    * @return sorted collection of all revision data information of entity.
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    */
   <T extends AbstractPersistentEntity> List<RevisionData<T>> loadAllRevisions(
            Class<T> entityClass, long uniqueIdentifier) throws DataAccessException;

   /**
    * looking entity's revision historical data by given date(maximum date less or equals given) -
    * the most up to date revision will be picked.
    * <p/>
    * This method allows you to pass multiple primary keys and result will be map where keys are
    * unique identifiers.
    * <p/>
    * May be useful - result map is actually LinkedHashMap(so ordered according to unique
    * identifiers collection).
    * <p/>
    * Also please note that in case when no revision data found for particular identified, nothing
    * will be added to result map.
    * 
    * @param entityClass
    *           domain class
    * @param date
    *           historical data date
    * @param uniqueIdentifiers
    *           collection of unique identifiers
    * @param property
    *           date property to be used(if not specified revision timestamp will be used)
    * @param <T>
    *           type of entity
    * @return map where key is unique identifier and value is revision data
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    */
   <T extends AbstractPersistentEntity> Map<Long, RevisionData<T>> latestRevisionForDate(
            Class<T> entityClass, Date date, Collection<Long> uniqueIdentifiers, String property)
            throws DataAccessException;

   /**
    * looking entity's revision historical data by given date(maximum date less or equals given) -
    * the most up to date revision will be picked.
    * 
    * @param entityClass
    *           domain class
    * @param date
    *           historical data date
    * @param uniqueIdentifier
    *           primary key of entity
    * @param property
    *           date property to be used(if not specified revision timestamp will be used)
    * @param <T>
    *           type of entity
    * @return revision data for unique identifier or <code>NULL</code> if nothing found.
    * @throws org.springframework.dao.DataAccessException
    *            any jdbc exception.
    */
   <T extends AbstractPersistentEntity> RevisionData<T> latestRevisionForDate(Class<T> entityClass,
            Date date, long uniqueIdentifier, String property) throws DataAccessException;

   IHibernateOperations getLocalHibernateTemplate();
}
